package utils

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"io/ioutil"
	"math/rand"
	"time"
)

func ResolveServiceRootKey() string {
	return "/services"
}

func ResolveServiceKey(name, key string) string {
	return ResolveServiceRootKey() + "/" + name + "/" + key
}

func ResolveService(name string) string {
	return ResolveServiceRootKey() + "/" + name
}

func LoadConfig(filename string, v interface{}) error {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}
	return json.Unmarshal(data, v)
}

func PrintMap(m map[interface{}]interface{}) {
	for k, v := range m {
		fmt.Printf("k = %v, v= %v", k, v)
	}
}

type Claims struct {
	Uid int64 `json:"uid,string"`
	jwt.StandardClaims
}

func CreateToken(uid int64, secret string) (string, error) {

	nowTime := time.Now()
	expireTime := nowTime.Add(3 * time.Hour)
	claims := Claims{
		uid,
		jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(),
			Issuer:    "gin-blog",
		},
	}

	at := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	token, err := at.SignedString([]byte(secret))
	if err != nil {
		return "", err
	}
	return token, nil
}

func ParseToken(token string, secret string) (*Claims, error) {
	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (i interface{}, err error) {
		return []byte(secret), nil
	})
	if tokenClaims != nil {
		if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
			return claims, nil
		}
	}
	return nil, err
}

func Md5(str string) string {
	h := md5.New()
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum(nil))
}

var methodsMap = map[string]uint8{
	"Get":    0,
	"Post":   1,
	"Put":    2,
	"Patch":  3,
	"Delete": 4,
}

var methodsArray = map[uint8]string{
	0: "Get",
	1: "Post",
	2: "Put",
	3: "Patch",
	4: "Delete",
}

func SetPromise(methods ...string) uint8 {
	value := 0
	for _, method := range methods {
		if _, ok := methodsMap[method]; ok {
			value |= 1 << methodsMap[method]
		}
	}
	return uint8(value)
}

func GetPromise(value uint8) []string {
	var methods []string
	for k, v := range methodsArray {
		if value>>k&1 == 1 {
			methods = append(methods, v)
		}
	}
	return methods
}

func Rand(n int) int {
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(n)
}
